package services;

import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.UUID;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import repositories.ProjectRepository;
import domain.Project;
import domain.Registration;
import domain.User;
import domain.UserGroup;
import domain.Vacancy;
import forms.ProjectForm;

@Service
@Transactional
public class ProjectService {

	//Managed Repository
	@Autowired
	private ProjectRepository projectRepository;
	
	//Supporting Services
	@Autowired
	private UserService userService;
	
	//Constructors
	public ProjectService(){
		super();
	}
	
	//Simple CRUD methods
	public Project create(){
		Project result;
		User creator;
		String referenceNumber;
		String code;
		Date currentMoment;
		Collection<User> followers;
		Collection<Registration> registrations;
		Collection<Vacancy> vacancies;
		
		creator = userService.findByPrincipal();
		code = UUID.randomUUID().toString();
		referenceNumber = creator.getSurname() + code;
		currentMoment = new Date();
		
		followers = new HashSet<User>();
		registrations = new HashSet<Registration>();
		vacancies = new HashSet<Vacancy>();
		
		result = new Project();
		result.setReferenceNumber(referenceNumber);
		result.setCreationMoment(currentMoment);
		result.setTotalAmountOfWork(null);
		result.setStatus("Creating");
		result.setCreator(creator);
		result.setFollowers(followers);
		result.setRegistrations(registrations);
		result.setVacancies(vacancies);
		
		return result;
	}
	
	public Collection<Project> findAll(){
		Collection<Project> result;
		
		result = projectRepository.findAll();
		
		return result;
	}
	
	public Project findOne(int projectId){
		Project result;
		
		result = projectRepository.findOne(projectId);
		
		return result;
	}
	
	public void save(Project project){
		Assert.notNull(project);
		Assert.notNull(project.getVacancies());
		Assert.isTrue(project.getCreator().equals(userService.findByPrincipal()));
		Assert.isTrue(project.getStartMoment().after(project.getCreationMoment()));
		Assert.isTrue(project.getEndMoment().after(project.getStartMoment()));
		
		projectRepository.save(project);
	}
	//Other Business methods
	
	public Collection<Project> findNotFinishedProjects(){
		Collection<Project> result;
		
		result = projectRepository.findNotFinishedProjects();
		
		return result;
	}
	
	public Collection<Project> findAvailableProjects(){
		Collection<Project> result;
		UserGroup userGroup;
		
		userGroup = userService.findByPrincipal().getUserGroup();
		Assert.notNull(userGroup);
		result = projectRepository.findAvailableProjectsForGroup(userGroup.getId());
		
		return result;
	}
	
	public Collection<Project> findJoinedProjects(){
		Collection<Project> result;
		User user;
		
		user = userService.findByPrincipal();
		result = projectRepository.findJoinedProjects(user.getId());
		
		return result;
	}
	
	public Collection<Project> findCreatedProjects(){
		Collection<Project> result;
		User user;
		
		user = userService.findByPrincipal();
		result = projectRepository.findCreatedProjects(user.getId());
		
		return result;
	}
	
	public Collection<Project> findFollowedProjects(){
		Collection<Project> result;
		User user;
		
		user = userService.findByPrincipal();
		result = projectRepository.findFollowedProjects(user.getId());
		
		return result;
	}
	
	public void finishCreate (Project project){
		Assert.notNull(project);
		Assert.isTrue(projectRepository.exists(project.getId()));
		Assert.isTrue(project.getCreator().equals(userService.findByPrincipal()));
		Assert.isTrue(project.getStatus().equals("Creating"));
		Assert.isTrue(!project.getVacancies().isEmpty());
		Collection<Vacancy> vacancies = project.getVacancies();
		for(Vacancy v: vacancies){
			Assert.isTrue(v.getPeopleRequired()>0);
		}
		
		project.setStatus("Recruiting");
		save(project);
		
	}
	
	public void finishProject (Project project){
		Assert.notNull(project);
		Assert.isTrue(projectRepository.exists(project.getId()));
		Assert.isTrue(project.getCreator().equals(userService.findByPrincipal()));
		Assert.isTrue(project.getStatus().equals("Started"));
		
		project.setStatus("Finished");
		save(project);
		
	}
	
	public void followProject (Project project){
		User user;
		Assert.notNull(project);
		Assert.isTrue(projectRepository.exists(project.getId()));
		Assert.isTrue(!project.getFollowers().contains(userService.findByPrincipal()));
		Assert.isTrue(project.getStatus().equals("Started"));
		
		user = userService.findByPrincipal();
		
		user.getFollowedProjects().add(project);
		project.getFollowers().add(user);
		
		userService.save(user);
		projectRepository.save(project);
		
	}
	
	public void unfollowProject(Project project){
		User user;
		Assert.notNull(project);
		Assert.isTrue(projectRepository.exists(project.getId()));
		Assert.isTrue(project.getFollowers().contains(userService.findByPrincipal()));
		Assert.isTrue(project.getStatus().equals("Started"));
		
		user = userService.findByPrincipal();
		
		user.getFollowedProjects().remove(project);
		project.getFollowers().remove(user);
		
		userService.save(user);
		projectRepository.save(project);
		
	}
	
	//Object Form methods
	public Project reconstruct(ProjectForm projectForm){
		Assert.notNull(projectForm);
		Project result;
		if(projectForm.getId()==0){
			result = create();
		}else{
			result = findOne(projectForm.getId());
		}
		result.setReferenceNumber(projectForm.getReferenceNumber());
		result.setCreationMoment(projectForm.getCreationMoment());
		result.setTitle(projectForm.getTitle());
		result.setDescription(projectForm.getDescription());
		result.setGoal(projectForm.getGoal());
		result.setStartMoment(projectForm.getStartMoment());
		result.setEndMoment(projectForm.getEndMoment());
		result.setTotalAmountOfWork(projectForm.getTotalAmountOfWork());
		result.setStatus(projectForm.getStatus());
		
		return result;
	}
	
	public ProjectForm projectToForm(Project project){
		Assert.notNull(project);
		ProjectForm result;
		
		result = new ProjectForm();
		
		result.setId(project.getId());
		
		result.setCreator(project.getCreator());
		result.setReferenceNumber(project.getReferenceNumber());
		result.setCreationMoment(project.getCreationMoment());
		result.setTitle(project.getTitle());
		result.setDescription(project.getDescription());
		result.setGoal(project.getGoal());
		result.setStartMoment(project.getStartMoment());
		result.setEndMoment(project.getEndMoment());
		result.setTotalAmountOfWork(project.getTotalAmountOfWork());
		result.setStatus(project.getStatus());
		
		return result;
	}
}
